package com.lonely.system.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lonely.common.core.domain.auth.LoginBodyDto;
import com.lonely.common.core.domain.auth.LoginUser;
import com.lonely.common.core.domain.auth.UserMsgDto;
import com.lonely.system.domain.entity.SysMenu;
import com.lonely.system.domain.entity.SysUser;
import com.lonely.common.enums.UserStatus;
import com.lonely.common.exception.AuthException;
import com.lonely.common.exception.BaseException;
import com.lonely.common.utils.FzzfDateUtil;
import com.lonely.common.utils.ServletUtils;
import com.lonely.common.utils.ip.IpUtils;
import com.lonely.framework.web.service.TokenService;
import com.lonely.system.domain.vo.auth.UserInfoVo;
import com.lonely.system.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author: 黄志标
 * @date: 2025/6/27 10:32
 * @description: 身份认证接口实现
 */
@Service
@Slf4j
public class AuthenticationServiceImpl implements IAuthenticationService {

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private ISysDataPermissionsService sysDataPermissionsService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysMenuService menuService;

    /**
     * 用户登录
     *
     * @param loginBody
     * @return
     */
    @Override
    public String login(LoginBodyDto loginBody) {
        LoginUser loginUser;
        try {
            loginUser = this.loadUserName(loginBody.getPhone(), loginBody.getPassword());
        } catch (Exception e) {
            log.error("登录失败,异常原因：{}", ExceptionUtils.getStackTrace(e));
//            AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginBody.getPhone(), Constants.LOGIN_FAIL, e.getMessage()));
            throw new AuthException(e.getMessage());
        }
//        AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginBody.getPhone(), Constants.LOGIN_SUCCESS, "登陆成功"));
        recordLoginInfo(loginUser.getUser());
        // 生成token
        return tokenService.createToken(loginUser);
    }

    /**
     * 退出登录
     */
    @Override
    public void logout() {
        LoginUser loginUser = tokenService.getLoginUser();
        tokenService.delLoginUser(loginUser.getToken());
    }

    /**
     * 获取登录的用户信息
     *
     * @return
     */
    @Override
    public UserInfoVo getUserInfo() {
        LoginUser loginUser = tokenService.getLoginUser();
        UserMsgDto user = loginUser.getUser();
        // 角色集合
        Set<String> roles = this.getRolePermission(user);
        // 按钮权限集合
        Set<String> permissions = this.getButtonPermission(user);
        // 菜单集合
        Set<String> menus = this.getMenuPermission(user);
        return new UserInfoVo().setUserId(user.getUserId()).setUserName(user.getUserName()).setRoles(roles).setButtons(permissions).setMenus(menus);
    }


    /**
     * 记录登录信息
     */
    private void recordLoginInfo(UserMsgDto user) {
        user.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        user.setLoginDate(FzzfDateUtil.getNowDate());

        SysUser oldUser = this.userService.getById(user.getUserId());
        oldUser.setLoginIp(user.getLoginIp());
        oldUser.setLoginDate(user.getLoginDate());
        userService.updateById(oldUser);
    }


    /**
     * 用户登录
     *
     * @param phone
     * @param password
     * @return
     */
    private LoginUser loadUserName(String phone, String password) {
        SysUser user = this.userService.getOne(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getPhone, phone)
                .ne(SysUser::getStatus, UserStatus.RESIGN.getCode())
        );

        // 前端通过 sha256加密后传入，后端不要再加密了，直接验证即可
//        String encryptedPassword= SecurityUtils.encryptPassword(password);
//        UserMsgDto user = userService.selectUserByUserName(phone);
        if (user == null) {
            log.info("登录用户：{} 不存在.", phone);
            throw new AuthException("登录用户：" + phone + " 不存在");
        } else if (!Objects.equals(password, user.getPassword())) {
            throw new AuthException("密码错误！");
        } else if (Objects.equals(UserStatus.DISABLE.getCode(), user.getStatus())) {
            log.info("登录用户：{} 已被停用.", phone);
            throw new BaseException("对不起，您的账号：" + phone + " 已停用");
        }
        return createLoginUser(user);
    }


    /**
     * 创建登录用户对象
     *
     * @param user
     * @return
     */
    private LoginUser createLoginUser(SysUser user) {
        UserMsgDto userMsgDto = new UserMsgDto();
        BeanUtils.copyProperties(user, userMsgDto);
        userMsgDto.setUserId(user.getId());

        LoginUser loginUser = new LoginUser(userMsgDto, this.getButtonPermission(userMsgDto));
        loginUser.setFactoryDataPermissions(this.sysDataPermissionsService.getFactoryDataPermissions(user.getId()));
        return loginUser;
    }


    /**
     * 获取角色数据权限
     *
     * @param user 用户信息
     * @return 角色权限信息
     */
    public Set<String> getRolePermission(UserMsgDto user) {
        Set<String> roles = new HashSet<>();
        // 管理员拥有所有权限
        if (user.isAdmin()) {
            roles.add("admin");
        } else {
            roles.addAll(roleService.selectRolePermissionByUserId(user.getUserId()));
        }
        return roles;
    }

    /**
     * 获取按钮数据权限
     *
     * @param user 用户信息
     * @return 菜单权限信息
     */
    public Set<String> getButtonPermission(UserMsgDto user) {
        Set<String> perms = new HashSet<>();
        // 管理员拥有所有权限
        if (user.isAdmin()) {
            perms.add("*:*:*");
        } else {
            perms.addAll(menuService.selectButtonPermsByUserId(user.getUserId()));
        }
        return perms;
    }


    /**
     * 获取菜单数据权限列表
     *
     * @param user 用户信息
     * @return 菜单权限信息
     */
    public Set<String> getMenuPermission(UserMsgDto user) {
        Set<String> perms = new HashSet<>();
        // 管理员拥有所有权限
        if (user.isAdmin()) {
            perms.addAll(this.menuService.list(new LambdaQueryWrapper<SysMenu>().ne(SysMenu::getMenuType, "F"))
                    .stream()
                    .map(SysMenu::getPath)
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.toSet()));
        } else {
            // 待根据用户id获取菜单权限
            perms.addAll(menuService.selectMenuPathByUserId(user.getUserId()));
        }
        return perms;
    }
}
